#ifndef JSON_DATA_H
#define JSON_DATA_H

#include <iostream>
#include <string>

enum JSON_Type {
	JSON_OBJECT = 0,
	JSON_ARRAY,
	JSON_STRING,
	JSON_NUMBER,
	JSON_BOOLEAN,
	JSON_NULL
};

class JSON_Abstract {
protected:
	std::string			_valueStr;
	JSON_Type			_type;
public:
	std::string			getValueAsString() { return _valueStr; };
	JSON_Type			getType() { return _type; }
};

class JSON_Object : public JSON_Abstract {
	// data will be held on _valueStr
	std::string::iterator startIt;
	std::string::iterator endIt;
public:
	JSON_Object(std::string str);
	JSON_Abstract *		getValueForKey(std::string name);
};

class JSON_Array : public JSON_Abstract {
	// data will be held on _valueStr
	std::string::iterator startIt;
	std::string::iterator endIt;
public:
	JSON_Array(std::string str);
	JSON_Abstract *		getValueById(unsigned int elementId);
	unsigned int		getElementCount();
};

class JSON_String : public JSON_Abstract {
	// data will be held on _valueStr
public:
	JSON_String(std::string str);
	std::string			str();
};

class JSON_Number : public JSON_Abstract {
	// data will be held on _valueStr
public:
	JSON_Number(std::string str);
	float				number();
};

class JSON_Boolean : public JSON_Abstract {
	// data will be held on _valueStr
public:
	JSON_Boolean(std::string str);
	bool				boolean();
};

class JSON_Null : public JSON_Abstract {
	// data will be held on _valueStr
public:
	JSON_Null(std::string str);
};

namespace json
{
	std::string		getKey(std::string::iterator& startIt, std::string::iterator& endIt);
	JSON_Abstract*	getValue(std::string::iterator& startIt, std::string::iterator& endIt);
	void			skipValue(std::string::iterator& startIt, std::string::iterator& endIt);
	void			skipString(std::string::iterator& startIt, std::string::iterator& endIt);
	void			skipObjectOrArray(std::string::iterator& startIt, std::string::iterator& endIt);
	void			removeSpaces(std::string::iterator& startIt, std::string::iterator& endIt);
	void			cleanUp(std::string::iterator& startIt, std::string::iterator& endIt);
	JSON_Abstract*	getObjectValue(std::string::iterator& startIt, std::string::iterator& endIt);
	JSON_Abstract*	getArrayValue(std::string::iterator& startIt, std::string::iterator& endIt);
	JSON_Abstract*	getStringValue(std::string::iterator& startIt, std::string::iterator& endIt);
	int				countObjectOrArrayElements(std::string::iterator& startIt, std::string::iterator& endIt);
	int				countStringElements(std::string::iterator& startIt, std::string::iterator& endIt);
}

#endif